﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using Pr0ject0.Models;
using Pr0ject0.ViewModel;

namespace Pr0ject0
{
    public class HiringSpecialistSessions
    {
        private enum State { Default, InterviewList, Interview, BackgroundList, ReferenceCheck, BackgroundCheck  }

        List<JobApplicationModel> interviewPool;
        List<JobApplicationModel> backgroundPool;
        Dictionary<string, State> states;
        Dictionary<string, List<JobApplicationModel>> interviewListCheckout;
        Dictionary<string, List<JobApplicationModel>> backgroundListCheckout;
        Dictionary<string, JobApplicationModel> interviewDetails;
        Dictionary<string, JobApplicationModel> backgroundChecks;
        Dictionary<string, List<ReferenceModel>> referenceLists;

        private volatile static HiringSpecialistSessions singleton;
        private static readonly object lockObj = new object();

        public static HiringSpecialistSessions GetInstance()
        {
            if (singleton == null)
            {
                lock (lockObj)
                {
                    if (singleton == null) singleton = new HiringSpecialistSessions();
                }
            }

            return singleton;
        }

        private HiringSpecialistSessions()
        {
            interviewPool = JobApplicationDB.GetInstance().GetStatusList(3);
            backgroundPool= JobApplicationDB.GetInstance().GetStatusList(5);
             

            states = new Dictionary<string, State>();
            this.interviewListCheckout = new Dictionary<string, List<JobApplicationModel>>();
            this.interviewDetails = new Dictionary<string, JobApplicationModel>();
            this.backgroundChecks = new Dictionary<string, JobApplicationModel>();
            this.backgroundListCheckout = new Dictionary<string, List<JobApplicationModel>>();
            this.referenceLists = new Dictionary<string, List<ReferenceModel>>();
        }

        public List<JobApplicationModel> GetInterviewList(string username)
        {
            int size = 5;
            List<JobApplicationModel> userList = null;
            JobApplicationModel[] array = new JobApplicationModel[size];

            if (Roles.IsUserInRole(username, "Hiring Specialist"))
            {
                ClearState(username);
                states[username] = State.InterviewList;

                if (interviewPool.Count > size)
                {
                    interviewPool.CopyTo(0, array, 0, size);
                    interviewPool.RemoveRange(0, size);
                }
                else
                {
                    interviewPool.CopyTo(0, array, 0, interviewPool.Count);
                    interviewPool.RemoveRange(0, interviewPool.Count);
                }
                userList = new List<JobApplicationModel>(array);
                interviewListCheckout[username] = userList;

                userList.RemoveAll(x => x == null);
            }

            return userList; 
        }

        public List<JobApplicationModel> GetBackgroundList(string username)
        {
            int size = 5;
            List<JobApplicationModel> userList = null;
            JobApplicationModel[] array = new JobApplicationModel[size];

            if (Roles.IsUserInRole(username, "Hiring Specialist"))
            {
                ClearState(username);
                states[username] = State.BackgroundList;

                if (backgroundPool.Count > size)
                {
                    backgroundPool.CopyTo(0, array, 0, size);
                    backgroundPool.RemoveRange(0, size);
                }
                else
                {
                    backgroundPool.CopyTo(0, array, 0, backgroundPool.Count);
                    backgroundPool.RemoveRange(0, backgroundPool.Count);
                }

                userList = new List<JobApplicationModel>(array);
                backgroundListCheckout[username] = userList;

                userList.RemoveAll(x => x == null);
            }

            return userList; 
        }

        public HiringSpecialistIndexModel GetIndexModel()
        {
            HiringSpecialistIndexModel model = new HiringSpecialistIndexModel();
            model.backgroundChecks = backgroundPool.Count;
            model.newApplications = interviewPool.Count;
            return model;
        }

        public JobApplicationModel InterviewApplicant(string username, int appid)
        {
            JobApplicationModel app = null;

            if (Roles.IsUserInRole(username, "Hiring Specialist") && states.ContainsKey(username))
            {
                if (interviewListCheckout.ContainsKey(username) && states[username] == State.InterviewList)
                {
                     app = interviewListCheckout[username].Find(x => x.ID == appid);

                    states[username] = State.Interview;
                    interviewListCheckout[username].RemoveAll(x => x.ID == appid);

                    foreach (JobApplicationModel j in interviewListCheckout[username])
                    {
                        if (!interviewPool.Contains(j))
                        {
                            interviewPool.Add(j);
                        }
                    }

                    interviewListCheckout.Remove(username);
                    interviewDetails[username] = app;
                }
                else
                {
                    throw new Exception("User is not in a valid state: " + State.InterviewList.ToString());
                }
            }
            else
            {
                throw new ArgumentException("user is not a hiring specialist or user has no state");
            }

            return app; //null until method completed
        }

        public void BeginReferenceCheck(string username, int appId)
        {
            ReferenceModel reference = null;

            if (Roles.IsUserInRole(username, "Hiring Specialist") && states.ContainsKey(username))
            {
                if (states[username] == State.BackgroundList && backgroundListCheckout.ContainsKey(username))
                {
                    JobApplicationModel app = backgroundListCheckout[username].Find(x => x.ID == appId);

                    states[username] = State.ReferenceCheck;
                    backgroundListCheckout[username].RemoveAll(x => x.ID == appId);

                    foreach (JobApplicationModel j in backgroundListCheckout[username])
                    {
                        if (!backgroundPool.Contains(j))
                        {
                            backgroundPool.Add(j);
                        }
                    }

                    backgroundListCheckout.Remove(username);

                    backgroundChecks[username] = app;
                    referenceLists[username] = new List<ReferenceModel>(app.references);
                }
                else
                {
                    throw new Exception("User is not in a valid state: " + State.BackgroundList);
                }
            }
            else
            {
                throw new ArgumentException("user is not a hiring specialist or user has no state");
            }
        }

        public ReferenceModel NextReference(string username)
        {
            ReferenceModel reference = null;

            if (Roles.IsUserInRole(username, "Hiring Specialist") && states.ContainsKey(username))
            {
                if (states[username] == State.ReferenceCheck
                    && referenceLists.ContainsKey(username) && backgroundChecks.ContainsKey(username))
                {
                    reference = referenceLists[username].Find(x => !x.isCalled);

                    if (reference != null)
                    {
                        referenceLists[username].Remove(reference);
                    }
                    else
                    {
                        states[username] = State.BackgroundCheck;
                    }
                }
                else
                {
                    throw new Exception("User is not in a valid state: " + State.ReferenceCheck);
                }
            }
            else
            {
                throw new ArgumentException("user is not a hiring specialist or user has no state");
            }

            return reference;
        }

        public JobApplicationModel CurrentApplication(string username)
        {
            if (states[username] == State.BackgroundCheck || states[username] == State.ReferenceCheck) 
            {
                return backgroundChecks[username];
            }else if( states[username] == State.Interview)
            {
                return interviewDetails[username];
            }

            return null; //null until method completed
        }

        public List<ReferenceModel> GetReferenceList(string username)
        {
            List<ReferenceModel> list = null;

            if (Roles.IsUserInRole(username, "Hiring Specialist") && states.ContainsKey(username))
            {
                if (states[username] == State.BackgroundCheck || states[username] == State.ReferenceCheck)
                {
                    list = backgroundChecks[username].references;
                }
            }

            return list;
        }

        public void ClearState(string username)
        {
            List<JobApplicationModel> list;

            if (Roles.IsUserInRole(username, "Hiring Specialist") && states.ContainsKey(username))
            {
                if (states[username] == State.InterviewList)
                {
                    list = interviewListCheckout[username];

                    foreach (JobApplicationModel j in list)
                    {
                        if (!interviewPool.Contains(j))
                        {
                            interviewPool.Add(j);
                        }
                    }

                    interviewListCheckout.Remove(username);
                    states[username] = State.Default;
                }
                else if (states[username] == State.BackgroundList)
                {
                    list = backgroundListCheckout[username];

                    foreach (JobApplicationModel j in list)
                    {
                        if (!backgroundPool.Contains(j))
                        {
                            backgroundPool.Add(j);
                        }
                    }

                    backgroundListCheckout.Remove(username);
                    states[username] = State.Default;
                }
                else if (states[username] == State.Interview)
                {
                    interviewDetails.Remove(username);
                    states[username] = State.Default;
                }
                else if (states[username] == State.ReferenceCheck || states[username] == State.BackgroundCheck)
                {
                    backgroundChecks.Remove(username);
                    referenceLists.Remove(username);
                    states[username] = State.Default;
                }
            }
        }

    }
}